package org.aerie.forest.core.brick.exception;

import java.time.LocalDateTime;
import java.util.Optional;

import org.aerie.forest.core.brick.exception.custom.MissSubExceptionPackException;

/**
 * 
 * @description 异常包装【将异常包装起来，用包装异常处理器处理】======会忽略抑制异常(以及)包装可抛物中的异常包装所包装的可抛物
 *
 * @author quark
 * @organization aerie
 * @date 2020年2月11日 上午12:02:03
 * @version 1.2.0
 */
public class ExceptionPack extends Exception {

	/**
	 * @description 序列化编号
	 * 
	 * @author quark
	 * @date 2020年2月17日 上午11:54:03
	 * @version 1.2.0
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * @description 需要被包装处理的异常
	 * 
	 * @author quark
	 * @date 2020年2月17日 上午11:54:21
	 * @version 1.2.0
	 */
	private final Exception exception;

	/**
	 * @description 异常的等级【默认值由forest环境配置】
	 * 
	 * @author quark
	 * @date 2020年2月17日 上午11:54:35
	 * @version 1.2.0
	 */
	private ExceptionGradeEnum exceptionGradeEnum = ExceptionGradeEnum.WARN;

	/**
	 * @description 异常包装生成的时间
	 * 
	 * @author quark
	 * @date 2020-7-23 15:22:38
	 * @version 2.0.1
	 */
	private final LocalDateTime generatedTime;

	/**
	 * @description 生成异常的线程的
	 * 
	 * @author quark
	 * @date 2020-7-23 15:39:34
	 * @version 2.0.1
	 */
	private final String threadName;

	/**
	 * 
	 * Construction
	 * 
	 * @param message   异常包装的异常信息
	 * @param exception 包装的异常
	 *
	 * @author quark
	 * @date 2020年2月11日 上午12:04:45
	 * @version 1.2.0
	 */
	public ExceptionPack(String message, Exception exception) {
		super(Optional.ofNullable(message).filter(p1 -> !p1.isEmpty()).orElse(">--异常包装丢失异常信息--<"));
		this.exception = Optional.ofNullable(exception).orElse(new MissSubExceptionPackException());
		adjustExceptionGrade(exception);
		generatedTime = LocalDateTime.now();
		threadName = Thread.currentThread().getName();
	}

	/**
	 * 
	 * Construction
	 * 
	 * @param message            异常包装的异常信息
	 * @param exceptionGradeEnum 异常的等级
	 * @param exception          包装的异常
	 * 
	 * @author quark
	 * @date 2020年2月11日 上午12:05:06
	 * @version 1.2.0
	 */
	public ExceptionPack(String message, ExceptionGradeEnum exceptionGradeEnum, Exception exception) {
		super(Optional.ofNullable(message).filter(p1 -> !p1.isEmpty()).orElse(">--异常包装丢失异常信息--<"));
		this.exceptionGradeEnum = Optional.ofNullable(exceptionGradeEnum).orElse(ExceptionGradeEnum.WARN);
		this.exception = Optional.ofNullable(exception).orElse(new MissSubExceptionPackException());
		adjustExceptionGrade(exception);
		generatedTime = LocalDateTime.now();
		threadName = Thread.currentThread().getName();
	}

	/**
	 * 
	 * @description 调整异常等级
	 * @param exception 需要调整异常等级的异常
	 *
	 * @author quark
	 * @date 2020年2月11日 上午12:09:56
	 * @version 1.2.0
	 */
	private void adjustExceptionGrade(Exception exception) {
		// 当包装的是异常包的时候，异常包的异常等级不能小于内部异常包的异常等级
		if (ExceptionPack.class.isInstance(exception)) {
			ExceptionGradeEnum exceptionPackGradeEnum = ((ExceptionPack) exception).getExceptionGradeEnum();
			if (exceptionPackGradeEnum.getGRADE() > this.exceptionGradeEnum.getGRADE())
				this.exceptionGradeEnum = exceptionPackGradeEnum;
		} else if (RuntimeException.class.isInstance(exception)) {
			this.exceptionGradeEnum = ExceptionGradeEnum.ERROR;
		}
	}

	/**
	 * 
	 * @description 获得包装的异常
	 * @return 包装的异常
	 *
	 * @author quark
	 * @date 2020年2月11日 上午12:10:24
	 * @version 1.2.0
	 */
	public Exception getException() {
		return exception;
	}

	/**
	 * 
	 * @description 获得异常的等级
	 * @return 异常包的等级
	 *
	 * @author quark
	 * @date 2020年2月11日 上午12:10:39
	 * @version 1.2.0
	 */
	public ExceptionGradeEnum getExceptionGradeEnum() {
		return exceptionGradeEnum;
	}

	/**
	 * @description 获得异常包装生成的时间
	 * @return 异常包装生成的时间
	 *
	 * @author quark
	 * @date 2020-7-23 15:23:05
	 * @version 2.0.1
	 */
	public LocalDateTime getGeneratedTime() {
		return generatedTime;
	}

	/**
	 * @description 获得当前线程的名称
	 * @return 当前线程的名称
	 *
	 * @author quark
	 * @date 2020-7-23 15:49:08
	 * @version 2.0.1
	 */
	public String getThreadName() {
		return threadName;
	}
}
